import httplib
import urllib
import urllib2
import urllib2_file

import sys, traceback

from xml.sax import saxutils
from xml.dom import minidom

debug_on = False;

def debug_on():
	debug_on = True

def debug_off():
	debug_on = False

def debug(message):
	if debug_on:
		print message



class OmixedQuery:
	
	# use these to define query returnType in your itemFind() calls
	ITEM_ID = "ITEM_ID";
	ITEM_WITH_TAGS = "ITEM_WITH_TAGS";
	SHORT_ITEM_DETAILS = "SHORT_ITEM_DETAILS";
	FULL_ITEM_DETAILS = "FULL_ITEM_DETAILS";
	ITEM_GRAPH = "ITEM_GRAPH";



"""
	A a base client containing all the methods needed for rest calls and result parsing to omixed services.
"""
class BaseClient(object):
	# must inherit from type or object to be a funky new style class, which can accept super calls.
	
	def __init__(self, baseURL, servicePath):
		self.baseURL = baseURL
		self.servicePath = servicePath
		
	# web-service call
	def callPost (self, url, data):
		
		try:
			request = urllib2.Request(url, data) 
			
			opener = urllib2.build_opener(DefaultErrorHandler())
			datastream = opener.open(request)
			body = datastream.read()
			
			# print url
			# print data
			# print body
			
			self.checkForErrors(body)
			
			# if a status code has been returned
			if hasattr(datastream, "status"):
				# raise an omixed exception
				raise OmixedException, self.parseString(body)
			
			return body
			
		except OmixedServerException, ose:
			raise ose
		except OmixedException, oe:
			raise oe
		except:
		    print "Unexpected error:", sys.exc_info()[0]
		else:
			datastream.close()
		
	
	# parses a returned document body and raises errors it finds
	def checkForErrors(self,xml):
		try:
			xmldoc = minidom.parseString(xml)
			if xmldoc.firstChild.nodeName == "soapenv:Fault":
				raise OmixedServerException, xmldoc
		except OmixedServerException, ose:
			raise ose
		except Exception, e:
			raise OmixedException, "Not an XML document? is the path correct? \n" + xml
	
	# determines the service url for a particular method
	def getservicePath(self, serviceName):
		url = self.baseURL + self.servicePath + serviceName
		return url
	
	# parses returns that are xml
	def parseInnerXML(self, xml):
		xmlStr = self.parseString(xml)
		if xmlStr != None:
			# return a valid xml document
			xmlInnerDoc = minidom.parseString(xmlStr)
			return xmlInnerDoc
	
	# parses return strings
	def parseString(self, xml):
		xmldoc = minidom.parseString(xml)
		xmlString = ""
		if len(xmldoc.firstChild.childNodes) > 0:
			if xmldoc.firstChild.childNodes[0].hasChildNodes():
				xmlString = xmldoc.firstChild.childNodes[0].childNodes[0].toxml()
				return xmlString
	
	# parses returned arrays
	def parseArray(self, xml):
		xmldoc = minidom.parseString(xml)
		myArray = []
		xmls = xmldoc.firstChild.childNodes
		for returnxml in xmls:
			xText = returnxml.firstChild.toxml()
			myArray.append(xText)
		return myArray



"""
	A client for calling omixed admin API.
"""
class OmixedAdminClient(BaseClient):
	
	# supply a base url to the server on initialisation
	def __init__(self, baseURL, adminUserName, adminPassword):
		super(OmixedAdminClient, self).__init__(baseURL, "/omixed/admin/")
		self.adminUserName = adminUserName
		self.adminPassword = adminPassword
	
	def adminCall(self, methodName, methodParameters = {}):
		url = self.getservicePath(methodName)
		values = {'adminUserName' : self.adminUserName,
		          'adminPassword' : self.adminPassword
		}
		for key in methodParameters.keys():
			values[key] = methodParameters[key]
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		return result
	
	def serverDescribe(self):
		result = self.adminCall("serverDescribe")
		resultString = self.parseString(result)
		results = resultString.split(" ; ")
		return results
	
	def resourceCreate(self, resourceName):
		return self.parseString(self.adminCall("resourceCreate", {
		  "resourceName": resourceName
		}))
	
	def resourceSetSchema(self, resourceName, schemaUrlOrXml):
		return self.parseString(self.adminCall("resourceSetSchema", {
		  "resourceName": resourceName, 
		  "schemaUrlOrXml" : schemaUrlOrXml 
		}))
		
	def resourceDelete(self, resourceName):
		return self.parseString(self.adminCall("resourceDelete", {
		  "resourceName": resourceName
		}))
	
	def resourceEmpty(self, resourceName):
		return self.parseString(self.adminCall("resourceEmpty", {
		  "resourceName": resourceName
		}))
	
	def resourceBackup(self, resourceName, fileName):
		return self.parseString(self.adminCall("resourceBackup", {
		  "resourceName": resourceName,
		  "fileName" : fileName
		}))
	
	def resourceRestore(self, resourceName, fileName):
		return self.parseString(self.adminCall("resourceRestore", {
		  "resourceName": resourceName,
		  "fileName" : fileName
		}))
	
	def userCreate(self, userName, password, userClass):
		return self.parseString(self.adminCall("userCreate", {
		  "userName": userName,
		  "password" : password,
		  "userClass" : userClass
		}))
	
	def policyAddOnResource(self, directive, privilege, grantedTo, onResource):
		# note deliberate typo : policyAddOnResourc
		return self.parseString(self.adminCall("policyAddOnResource", {
		  "directive": directive,
		  "privilege" : privilege,
		  "grantedTo" : grantedTo,
		  "onResource" : onResource
		}))
	

"""
	A client for calling omixed server API.
"""
class OmixedClient(BaseClient):
	
	
	# supply a base url to the server on initialisation
	def __init__(self, baseURL):
		super(OmixedClient, self).__init__(baseURL, "/omixed/server/")
		
		#self.__baseURL = baseURL
		#self.__servicePath = "/omixed/server/"
		
		self.__filePath = self.servicePath + "fileUpload"
		
		self.__resourceName = ""
		self.__userName = ""
		
		self.__sessionID = ""
		self.__domainName = None
		self.__itemTypes = []
		self.__itemDetails = {}
		self.__visibleFiles = []
		self.__schemas = {}
	
	
	
	def getSessionID(self):
		return self.__sessionID
	
	def getUserName(self):
		return self.__userName
	
	def getResourceName(self):
		return self.__resourceName
	
	# allows you to pass an existing session to a new client object (instead of connecting)
	def setExistingSession(self, sessionID, userName,resourceName):
		self.__resourceName = resourceName
		self.__userName = userName
		self.__sessionID = sessionID
	
	
	def makeItemID(self, itemType, itemOwner = "", itemName = ""):
		sep = "/"
		itemID = self.getDomainName() + sep + self.__resourceName + sep + itemType
		if itemOwner != "":
			itemID += sep + itemOwner
			if itemName != "":
				itemID += sep + itemName
		return itemID
		
	def getTypeFromID(self, itemID):
		return itemID.split("/")[2]
	
	
	
	#################################################################################
	#
	# WEB SERVICE API METHODS
	#
	#################################################################################
	
	
	
	
	# connect to the resource
	def connect(self, resourceName, userName, password):
		url = self.getservicePath("connect")
		
		self.__resourceName = resourceName
		self.__userName = userName
		
		values = {'resourceName' : self.__resourceName,
		          'userName' : self.__userName,
		          'password' : password 
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		connectionDetails = self.parseInnerXML(result)
		
		for node in connectionDetails.firstChild.childNodes:
			nodeName = node.nodeName
			if nodeName == "SessionID":
				self.__sessionID = node.firstChild.toxml()
			elif nodeName == "ServerDomainName":
				self.__domainName = node.firstChild.toxml()
			elif nodeName == "ServerAPIVersion":
				self.__serverAPIVersion = node.firstChild.toxml()
		
		return self.__sessionID
	
	
	# disconnect from the resource
	def disconnect(self):
		url = self.getservicePath("disconnect")
		
		values = { 'sessionID' : self.__sessionID }
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		__sessionID = ""
		__userName = ""
		__resourceName = ""
		
		return self.parseString(result)
	
	def getDomainName(self):
		return self.__domainName
	
	# get the item types for the connected resource
	def schemaEnumerateItemTypes(self):
		url = self.getservicePath("schemaEnumerateItemTypes")
		
		values = { 'sessionID' : self.__sessionID }
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		self.__itemTypes = self.parseArray(result)
		
		return self.__itemTypes
	
	
	# ALL REPLACED BY itemFind()
	
	# def getItemIDs(self,partialItemID):
	# 		url = self.getservicePath("getItemIDs")
	# 		
	# 		values = { 'sessionID' : self.__sessionID,
	# 		           'partialItemID' : partialItemID
	# 		}
	# 		eValues = urllib.urlencode(values)
	# 		
	# 		result = self.callPost(url, eValues)
	# 
	# 		self.__itemIDs = self.parseArray(result)
	# 
	# 		return self.__itemIDs
	# 	
	# 	
	# 	# get the item ids for a particular item type
	# 	# not in the server api
	# 	def getItemIDsForItemType(self,itemType):
	# 		url = self.getservicePath("getItemIDs")
	# 		
	# 		partialItemID = self.getItemIDFromType(itemType)
	# 		
	# 		values = { 'sessionID' : self.__sessionID,
	# 		           'partialItemID' : partialItemID
	# 		}
	# 		eValues = urllib.urlencode(values)
	# 		
	# 		# print url
	# 		# 		print eValues
	# 		
	# 		result = self.callPost(url, eValues)
	# 		
	# 		self.__itemIDs = self.parseArray(result)
	# 		
	# 		return self.__itemIDs
	# 	
	# 	
	# 	
	# 	# get the details for an item
	# 	def getItems(self,partialItemID, linkExpansionDepth = 0):
	# 		url = self.getservicePath("getItems")
	# 		
	# 		values = { 'sessionID' : self.__sessionID,
	# 		           'partialItemID' : partialItemID,
	# 		           'linkExpansionDepth':linkExpansionDepth
	# 		}
	# 		eValues = urllib.urlencode(values)
	# 		result = self.callPost(url, eValues)
	# 		
	# 		# print "result"
	# 		# print result
	# 		
	# 		itemsXML = self.parseInnerXML(result)
	# 		
	# 		items_array = []
	# 		
	# 		if itemsXML != None:
	# 			for itemXML in itemsXML.firstChild.childNodes:
	# 			
	# 				itemID = itemXML.attributes["itemID"].value
	# 				
	# 				# print itemID
	# 				# 				print itemXML.toxml()
	# 				# 				print "--------"
	# 				
	# 				item = OmixedItem()
	# 				item.setupXML(self, itemID, itemXML)
	# 				self.__itemDetails[itemID] = item
	# 				
	# 				# print item.getXML().toxml()
	# 				
	# 				items_array.append(item)
	# 		
	# 		return items_array
	# 	
	# 	
	
	# returns a list of FileInfo objects
	def fileEnumerate(self):
		
		url = self.getservicePath("fileEnumerate")
		
		values = { 'sessionID' : self.__sessionID }
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		fileXMLs = self.parseInnerXML(result)
		
		if fileXMLs != None:
			for fileXML in fileXMLs.firstChild.childNodes:
				fileInfo = FileInfo(fileXML)
				self.__visibleFiles.append(fileInfo)
		
		return self.__visibleFiles
	
	
	
	# returns a FileInfo object for a particular file ID
	def fileDescribe(self, fileID):
		url = self.getservicePath("fileDescribe")
		values = { 'sessionID' : self.__sessionID, 'fileID' : fileID }
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		# print "getFileDetails()"
		# print fileID
		fileXML = self.parseInnerXML(result)
		# print fileXML
		fileInfo = FileInfo(fileXML.firstChild)
		return fileInfo
	
	
	
	# returns the schema as an xml
	def schemaDescribeItemType(self, itemType):
		if self.__schemas.has_key(itemType) == False:
			url = self.getservicePath("schemaDescribeItemType")
		
			values = { 'sessionID' : self.__sessionID ,
			           'itemType' : itemType
			}
			eValues = urllib.urlencode(values)
			result = self.callPost(url, eValues)
			# print itemType
			# print result
			self.__schemas[itemType] = self.parseInnerXML(result)
		
		return self.__schemas[itemType]
	
	
	# generic search
	def itemFind(self, returnType, queryXML, queryOptions = ""):
		url = self.getservicePath("itemFind")
		
		values = { 'sessionID' : self.__sessionID,
		           'returnType' : returnType,
		           'queryXML': queryXML,
		           'queryOptions' : queryOptions
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		
		
		
		if returnType == OmixedQuery.ITEM_ID:
			resultXML = self.parseInnerXML(result)
			
			resultArray = []
			if resultXML.firstChild.firstChild:
				resultString = resultXML.firstChild.firstChild.toxml()
				resultArray = resultString.split("\n")
			return resultArray
		elif returnType == OmixedQuery.ITEM_GRAPH:
			return self.parseString(result)
		else:
			itemsXML = self.parseInnerXML(result)
			items_array = []
			if itemsXML != None:
				for itemXML in itemsXML.firstChild.childNodes:
				
					itemID = itemXML.attributes["itemID"].value
					
					# print itemID
					# 				print itemXML.toxml()
					# 				print "--------"
					
					item = OmixedItem()
					item.setupXML(self, itemID, itemXML)
					self.__itemDetails[itemID] = item
					
					# print item.getXML().toxml()
					
					items_array.append(item)
			
			return items_array
		
		
		
	
	# creates an item
	def itemCreate(self, omixedItem):
		url = self.getservicePath("itemCreate")
		
		xml = omixedItem.getXML().toxml()
		
		values = { 'sessionID' : self.__sessionID,
		           'itemID' : omixedItem.itemID,
		           'accessGroup': omixedItem.accessGroup,
		           'itemXML' : xml
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		return self.parseString(result)
	
	
	
	# creates an item
	def itemValidate(self, omixedItem, intendedForUpdate=False):
		url = self.getservicePath("itemValidate")
		
		ifu = "false"
		if intendedForUpdate == True:
			ifu = "true"
		
		xml = omixedItem.getXML().toxml()
		
		values = { 'sessionID' : self.__sessionID,
		           'itemID' : omixedItem.itemID,
		           'accessGroup': omixedItem.accessGroup,
		           'itemXML' : xml,
		           'intendedForUpdate': ifu
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		# print result
		return self.parseString(result)
	
	
	
	# updates an item
	def itemUpdate(self, omixedItem):
		url = self.getservicePath("itemUpdate")
		
		xml = omixedItem.getXML().toxml()
		
		values = { 'sessionID' : self.__sessionID,
		           'itemID' : omixedItem.itemID,
		           'accessGroup': omixedItem.accessGroup,
		           'itemXML' : xml
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		return self.parseString(result)
	
	
	
	# deletes an item
	def itemDelete(self, itemID):
		url = self.getservicePath("itemDelete")
		
		values = { 'sessionID' : self.__sessionID,
		           'itemID' : itemID
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		
		return self.parseString(result)
		
	# aquires a lock on an item
	def lockAcquire(self, itemID):
		url = self.getservicePath("lockAcquire")

		values = { 'sessionID' : self.__sessionID,
		           'itemID' : itemID
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		return self.parseString(result)
	
	# releases a lock on an item 
	def lockRelease(self, itemID):
		url = self.getservicePath("lockRelease")

		values = { 'sessionID' : self.__sessionID,
		           'itemID' : itemID
		}
		eValues = urllib.urlencode(values)
		result = self.callPost(url, eValues)
		return self.parseString(result)
	
	
	
	
	
	#################################################################################
	#
	# HTTP REQUESTS
	#
	#################################################################################
	
	
	
	# uploads a file and returns a fileID
	# uses urllib2_file
	def upload(self, filename, accessGroup="public"):
		
		data = {'sessionID' : self.__sessionID,
			'accessGroup': accessGroup,
			'file':  open(filename)
		}
		
		url = self.getservicePath("fileUpload") + "?sessionID=" + self.__sessionID
		
		try:
		
			response = urllib2.urlopen(url, data)
		
			read = response.read()
		
			messages = read.split(" : ")
		
			if messages[0] == "BAD":
				raise OmixedException, messages[1]
			return messages[1]
			
		except OmixedException, inst:
			# pass on any omixed exception values in a new omixed exception
			raise OmixedException, inst.value
		except Exception, inst:
			# pass on any other exceptions in a new exception
			raise OmixedException, "Could not upload file. " + str(inst), sys.exc_info()[2]
		else:
			response.close()
	
	
	
	
	
	
	# downloads a file, option to specify your own file name
	def download(self, fileID, filePath = "", fileName=None):
		
		data = {'sessionID' : self.__sessionID,
		        'fileID': fileID
		}
		
		url = self.getservicePath("fileDownload")
		
		try:
			response = urllib2.urlopen(url,data)
		
			read = response.read()
		
			if fileName == None:
				fileInfo = self.getFileInfo(fileID)
				if fileInfo != None:
					fileName = fileInfo.originalName
				else:
					raise OmixedException, "Unknown fileID " + fileID
			
			
			localFile = open(filePath + fileName, 'w')
			localFile.write(read)
			localFile.close()
		
			response.close()
		
		
		
			return localFile
		except OmixedException, inst:
			# pass on any omixed exception values in a new omixed exception
			raise OmixedException, inst.value
		except Exception, inst:
			# pass on any other exceptions in a new exception
			raise OmixedException, "Could not download file. " + str(inst), sys.exc_info()[2]
		else:
			response.close()
	
	
	
	
	
	#################################################################################
	#
	# UTILITIES
	#
	#################################################################################
	
	
	# for a particular item type, return the id
	def getItemIDFromType(self, itemType):
		sep = "/"
		itemID = self.__domainName + sep + self.__resourceName + sep + itemType
		return itemID
	
	
	
	
	
	
	




# taken from http://www.diveintopython.org/http_web_services/
class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):    
    def http_error_default(self, req, fp, code, msg, headers): 
        result = urllib2.HTTPError(                           
            req.get_full_url(), code, msg, headers, fp)       
        result.status = code                                   
        return result


# an exception reported by the server
class OmixedServerException(Exception):

	faultcode = "";
	faultstring = "";
	ErrorCode = "";
	ErrorClass = "";

	def __init__(self, xml):
		for x in xml.firstChild.childNodes:
			if x.nodeName == "faultcode":
				self.faultcode = x.firstChild.toxml()
			elif x.nodeName == "faultstring":
				self.faultstring = x.firstChild.toxml()
			elif x.nodeName == "detail":
				for xx in x.childNodes:
					if (xx.nodeName == "omixed:ErrorCode"):
						self.ErrorCode = xx.firstChild.toxml()
					elif (xx.nodeName == "omixed:ErrorClass"):
						self.ErrorClass = xx.firstChild.toxml()

	def __str__(self):
		return repr(self.faultstring)



class OmixedException(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)


# not sure what the mimetypes do here ...?
		import httplib, mimetypes


class FileInfo:
	
	fileID="" 
	format="" 
	accessGroup="" 
	originalName="" 
	ownerName="" 
	sizeInBytes="" 
	uploadTime=""
	
	def __init__(self, xml):
		# print xml.toxml()
		self.fileID = xml.attributes["fileID"].value
		self.format = xml.attributes["format"].value
		self.originalName = xml.attributes["originalName"].value
		self.sizeInBytes = xml.attributes["sizeInBytes"].value
		
		if xml.attributes.has_key("accessGroup"):
			self.accessGroup = xml.attributes["accessGroup"].value
			
		if xml.attributes.has_key("ownerName"):
			self.ownerName = xml.attributes["ownerName"].value
		
		if xml.attributes.has_key("uploadTime"):
			self.uploadTime = xml.attributes["uploadTime"].value
		
	def __str__(self):
		
		s = self.fileID + ":" + self.originalName
		
		return s


"""
	A class for locally caching the details of an item. 
"""
class OmixedItem:
	
	
	def __init__(self):
		self.__client = None

		self.itemID = ""
		self.__itemXML = None
		self.__itemType = ""
		self.accessGroup = ""

		self.__links = {}
		self.__attributes = {}
		self.__files = {}
		
		self.dodebug = False
		
		

	
	# create an omixed item from some xml
	# itemXML must be an XML node, not a document
	def setupXML(self, client, itemID, itemXML):
		self.__client = client
		self.itemID = itemID
		self.__itemXML = itemXML
		
		idSplit = self.itemID.split("/")

		self.__itemType = idSplit[2]
		
		if itemXML.attributes != None:
			if itemXML.attributes.has_key("accessGroup"):
				# print "setting access group"
				self.accessGroup = itemXML.attributes["accessGroup"].value
		
		self.__parseItemXML(itemXML)
	
	
	def changeResourceName(self,newResourceName):
		itemID = self.itemID
		itemIDSplit = itemID.split("/")
		itemIDSplit[1] = newResourceName
		self.itemID = "/".join(itemIDSplit)
		return self.itemID
		
	def changeOwner(self,newOwner):
		itemID = self.itemID
		itemIDSplit = itemID.split("/")
		itemIDSplit[3] = newOwner
		self.itemID = "/".join(itemIDSplit)
		return self.itemID
	
	
	# set up a totally new item
	def setupNewItem(self, client, itemType, itemName, accessGroup = "public"):
		
		domainName = client.getDomainName()
		user = client.getUserName()
		resourceName = client.getResourceName()
		sep = "/"
		
		itemID = domainName + sep + resourceName + sep + itemType + sep + user + sep + itemName
		newItemXML = minidom.parseString("<Item></Item>")
		
		newItemXML.firstChild.attributes["accessGroup"] = accessGroup
		
		# setupXML requires the XML document's first child, 
		# not the document itself
		self.setupXML(client, itemID, newItemXML.firstChild)
	
	
	
	
	
	
	
	
	
	def setAttribute(self, name, attributeValue):
			self.__attributes[name] = attributeValue
			if self.dodebug == True:
				print str(id(self)) + " set("+name+") " + self.itemID  + "    "+ self.__attributes[name]
		
		
		
	def getAttribute(self, name):
		if self.__attributes.has_key(name):
			if self.dodebug == True:
				print str(id(self)) + " get("+name+") " + self.itemID  + "    "+ self.__attributes[name]
			return self.__attributes[name]
		
	
	

	
	
	def setFileInfo(self, name, fileInfo):
		if self.__files.has_key(name) == False:
			self.__files[name] = []
		self.__files[name].append(fileInfo)
	
	def setFileID(self, name, fileID):
		if self.__files.has_key(name) == False:
			self.__files[name] = []
		fileInfo = self.__client.fileDescribe(fileID)
		self.__files[name].append(fileInfo)
	
	def removeFiles(self,name):
		self.__files[name] = []
	
	def getFiles(self, name):
		if self.__files.has_key(name):
			return self.__files[name]
	
	def getAllFiles(self):
		return self.__files
	
		
		
		
	def setLink(self, name, itemID):
		if self.__links.has_key(name) == False:
			self.__links[name] = []
		self.__links[name].append(itemID)

	def getLinks(self, name):
		if self.__links.has_key(name):
			return self.__links[name]
	
	def removeLinks(self,name):
		self.__links[name] = []
	
	def getAllLinks(self):
		return self.__links
	
	
	# parses an item's xml to store the details
	def __parseItemXML(self, itemXML):
		
		
		root = itemXML.childNodes
		self.__recurseXML(root)
		
		
	
	
	
	# used by __parseItemXML() to store the item's details
	def __recurseXML(self, xmlnode, path=None):
		for x in xmlnode:
			
			if (x.nodeType != 3):
				
				atts = x.attributes
				
				if atts.has_key("name"):
					
					nodeName = x.nodeName
					name = x.attributes["name"].value
					
					if path == None:
						newPath = name
					else:
						newPath = path + "." + name
				
					# print nodeName +":"+name
		
					if nodeName == "Attribute":
						self.setAttribute(newPath, x.firstChild.toxml())
					elif nodeName == "Link":
						self.setLink(newPath, x.attributes["itemID"].value)
					elif nodeName == "File":
						fileInfo = FileInfo(x)
						self.setFileInfo(newPath, fileInfo)
					elif nodeName == "Group":
						self.__recurseXML(x.childNodes, newPath)
	
	
	
	# returns the item's xml
	def getXML(self):
		
		
		schemaXML = self.__client.schemaDescribeItemType(self.__itemType)
		root = schemaXML.firstChild.childNodes

		newItemXML = minidom.parseString ("<Item></Item>")
		newItemXML.firstChild.attributes["itemID"] = self.itemID
		newItemXML.firstChild.attributes["accessGroup"] = self.accessGroup
		
		self.__recurseSchemaXML(root, newItemXML.firstChild, newItemXML)
		
		
		return newItemXML
	
	
	
	# used by getXML(), parses a schema to build the item's xml
	def __recurseSchemaXML(self, schemaNode, itemNode, itemDoc, path=None):
		for x in schemaNode:
			
			if (x.nodeType != 3):
				
				atts = x.attributes
				
				if atts.has_key("name"):
					
					nodeName = x.nodeName
					name = x.attributes["name"].value
					
					if path == None:
						newPath = name
					else:
						newPath = path + "." + name
						
					
					# print nodeName +":"+name + "\n"
					
					if nodeName == "Attribute":
						
						attValue = self.getAttribute(newPath)
						
						if attValue != None and attValue != "":
							
							n = itemDoc.createElement("Attribute")
							n.setAttribute("name", name)
							
							t = itemDoc.createTextNode(attValue)
							n.childNodes.append(t)
							
							itemNode.childNodes.append(n)
							
					elif nodeName == "Link":
						linkValues = self.getLinks(newPath)
						
						if linkValues != None:
							
							for linkValue in linkValues:
							
								n = itemDoc.createElement("Link")
								n.setAttribute("name", name)
								n.setAttribute("itemID", linkValue)
								itemNode.childNodes.append(n)
					
					elif nodeName == "File":
						fileInfos = self.getFiles(newPath)
						
						if fileInfos != None:
							for fileInfo in fileInfos:
								n = itemDoc.createElement("File")
								n.setAttribute("name", name)
								n.setAttribute("originalName", fileInfo.originalName)
								n.setAttribute("fileID", fileInfo.fileID)
								n.setAttribute("format", fileInfo.format)
								n.setAttribute("accessGroup", fileInfo.accessGroup)
								n.setAttribute("ownerName", fileInfo.ownerName)
								n.setAttribute("sizeInBytes", fileInfo.sizeInBytes)
								n.setAttribute("uploadTime", fileInfo.uploadTime)
								itemNode.childNodes.append(n)
						
					elif nodeName == "Group":
						
						n = itemDoc.createElement("Group")
						n.setAttribute("name", name)
						itemNode.childNodes.append(n)
						
						self.__recurseSchemaXML(x.childNodes, n, itemDoc, newPath)
	
	
	
	
	
	
	# the to string method
	def __str__(self):
		n ="\n"
		s = "itemID:" + n + self.itemID + n
		
		
		s += "Attributes:" + n 
		for attKey in self.__attributes.keys():
			s += " " + attKey + " - " + self.__attributes[attKey] + n
			
		s += "Links:" + n + self.__hashOfListsToString(self.__links)
		s += "Files:" + n + self.__hashOfListsToString(self.__files)
		
		# s += "Tags:" + n + str(self.__tags)
		
		return s
	
	
	
	# used by __str__
	def __hashOfListsToString(self, hl):

		n ="\n"
		s = ""

		for linkKey in hl.keys():
			s += linkKey + ":" + n

			for link in hl[linkKey]:
				s += " - " + link + n

		return s








# 
# class OmixedBackup:
# 
# 	def __init__(self, host, resourceName, userName, password):
# 		self.host = host
# 		self.resourceName = resourceName
# 		self.userName = userName
# 		self.password = password
# 
# 		self.client = OmixedClient(self.host)
# 		self.client.connect(self.resourceName, self.userName, self.password)
# 
# 	
# 	# the filePath is the folder you want to save your backup to
# 	# the fileName is the name of the backup xml file
# 	# partialItemIDs is an array of partialItemIDs
# 	# e.g. ["www.streptobase.org/demo_files/Study/", "www.streptobase.org/demo_files/Person/"]
# 	# please note that it will also have to save any linked 
# 	# items to maintain relational integrity
# 	def save(self, filePath, fileName, partialItemIDs = None):
# 		debug("saving")
# 		self.filePath = filePath
# 		self.itemXMLs = minidom.parseString ("<ItemList></ItemList>")
# 		self.savedItemIDs = []
# 		self.items = {}
# 
# 		# get all the database
# 		if partialItemIDs == None:
# 			itemTypes = self.client.getItemTypes()
# 			debug("backing up everything")
# 			debug(itemTypes)
# 			
# 			for itemType in itemTypes:
# 				items = self.client.getItems(self.client.makeItemID(itemType))
# 				for item in items:
# 					self.items[item.itemID] = item
# 		
# 		# get all the partial item ids requested
# 		else:
# 			debug("backing up partial")
# 			debug(partialItemIDs)
# 			
# 			for partialItemID in partialItemIDs:
# 				items = self.client.getItems(partialItemID)
# 				for item in items:
# 					self.items[item.itemID] = item
# 
# 		for itemID in self.items:
# 			debug(itemID)
# 			self.saveItem(self.items[itemID])
# 
# 		saveFile = open(filePath+fileName, 'w')
# 		saveFile.write(self.itemXMLs.toxml())
# 		saveFile.close()
# 		debug("saving complete")
# 
# 
# 
# 	def saveItem(self, item):
# 		itemID = item.itemID
# 
# 		# if this item has been saved before, return
# 		if itemID in self.savedItemIDs:
# 			debug(itemID + " already saved")
# 			return
# 		
# 
# 		itemXML = item.getXML().firstChild
# 
# 		# download any files
# 		itemFiles = item.getAllFiles()
# 		for fileTypeName in itemFiles:
# 			fileInfos = itemFiles[fileTypeName]
# 
# 			for fileInfo in fileInfos:
# 				self.client.download(fileInfo.fileID, self.filePath, fileInfo.originalName)
# 
# 		# save any links
# 		itemLinks = item.getAllLinks()
# 		for linkName in itemLinks:
# 			links = itemLinks[linkName]
# 			for link in links:
# 				if link not in self.savedItemIDs:
# 
# 					if self.items.has_key(link):
# 						linkItem = self.items[link]
# 					else:
# 						linkItem = self.client.getItems(link)[0]
# 		
# 					saved = self.saveItem(linkItem)
# 		
# 		debug(itemID)
# 		self.itemXMLs.firstChild.childNodes.append(itemXML)
# 		self.savedItemIDs.append(itemID)
# 
# 	
# 	def matchIDs(self, partialItemIDs, itemID):
# 		for partialItemID in partialItemIDs:
# 			if itemID.find(partialItemID) != -1:
# 				return True
# 		return False;
# 	
# 	def loadItem(self, item):
# 		itemID = item.itemID
# 		
# 		# if this item has been saved before, return
# 		if itemID in self.loadedItemIDs:
# 			debug(itemID + " already loaded")
# 			return 
# 		
# 		# upload any files
# 		itemFiles = item.getAllFiles()
# 		for fileTypeName in itemFiles:
# 			fileInfos = itemFiles[fileTypeName]
# 			
# 			item.removeFiles(fileTypeName)
# 			
# 			for fileInfo in fileInfos:
# 				fileInfo.fileID = self.client.upload(self.filePath + fileInfo.originalName)
# 				item.setFileInfo(fileTypeName,fileInfo)
# 		
# 		# load any dependent links
# 		itemLinks = item.getAllLinks()
# 		for linkName in itemLinks:
# 			links = itemLinks[linkName]
# 			
# 			item.removeLinks(linkName)
# 			
# 			for link in links:
# 				newLink = self.__changeResourceName(link, self.resourceName)
# 				newLink = self.__changeOwner(newLink, self.userName)
# 				linkItem = self.items[newLink]
# 				
# 				# if newLink not in self.loadedItemIDs:
# 				loaded = self.loadItem(linkItem)
# 				
# 				item.setLink(linkName,newLink)
# 				
# 				
# 		
# 		
# 		self.client.validate(item, False)
# 		self.client.create(item)
# 		debug("created " + itemID)
# 		self.loadedItemIDs.append(itemID)
# 		
# 	
# 	
# 	def __changeResourceName(self,itemID,newResourceName):
# 		itemIDSplit = itemID.split("/")
# 		itemIDSplit[1] = newResourceName
# 		newItemID = "/".join(itemIDSplit)
# 		return newItemID
# 	
# 	
# 	
# 	def __changeOwner(self,itemID,newOwner):
# 		itemIDSplit = itemID.split("/")
# 		itemIDSplit[3] = newOwner
# 		newItemID = "/".join(itemIDSplit)
# 		return newItemID
# 	
# 	
# 	# supply a filePath, where the back files are stored
# 	# a fileName for the backup xml file
# 	# partialItemIDs is an array of partialItemIDs
# 	# e.g. ["www.streptobase.org/demo_files/Result/"]
# 	# please note that it will also have to load any linked 
# 	# items to maintain relational integrity
# 	def load(self, filePath, fileName, partialItemIDs = None):
# 		debug("loading")
# 		self.filePath = filePath
# 		loadFile = open(filePath+fileName, 'r')
# 		itemXMLs = minidom.parseString (loadFile.read())
# 		self.loadedItemIDs = []
# 		self.items = {}
# 		
# 		if partialItemIDs != None:
# 			debug("only imported selected partial item ids")
# 			debug(partialItemIDs)
# 		
# 		for itemNode in itemXMLs.firstChild.childNodes:
# 			itemID = itemNode.attributes["itemID"].value
# 			
# 			itemType = self.client.getTypeFromID(itemID)
# 			
# 			item = OmixedItem()
# 			item.setupXML(self.client, itemID, itemNode)
# 			
# 			item.changeResourceName(self.resourceName)
# 			item.changeOwner(self.userName)
# 			
# 			self.items[item.itemID] = item
# 		
# 		
# 		
# 		for itemID in self.items:
# 			
# 			if partialItemIDs == None:
# 				matched = True
# 			else:
# 				matched = self.matchIDs(partialItemIDs, itemID)
# 			
# 			if matched == True:
# 				self.loadItem(self.items[itemID])
# 				
# 		debug("loading complete")
# 		









